#include <dsCvt.h>
// https://github.com/honrun/time
/*
 * Author: honrun
 */
/* 闰年 */
#ifndef USER_LEAP_YEAR
#define USER_LEAP_YEAR 1
#endif // LEAP_YEAR

/* 平年 */
#ifndef USER_COMMON_YEAR
#define USER_COMMON_YEAR 0
#endif // COMMON_YEAR

/* 判断是否为闰年 */
#define YEAR_LEAP(year) (((((year) % 4 == 0) && ((year) % 100 != 0)) || (((year) % 400 == 0) && ((year) % 3200 != 0)) || ((year) % 172800 == 0)) ? USER_LEAP_YEAR : USER_COMMON_YEAR)
/* 获取年份天数 */
#define DAYS_OF_THE_YEAR(year) (YEAR_LEAP(year) == USER_LEAP_YEAR ? 366 : 365)
/* 获取月份天数 */
#define DAYS_OF_THE_MONTH(year, month) ((((month) == 2) && (YEAR_LEAP(year) == USER_LEAP_YEAR)) ? 29 : dateMonthDays()[(month) - 1])

static const uint8_t *dateMonthDays()
{
    const static uint8_t yearMonthDays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    return yearMonthDays;
}
static uint8_t getWeek(tmdateType date)
{
    int32_t iCentury = 0;
    int8_t cWeek = 0;
    /* 如果是1、2月份，则需要把月份当作是上年度的13、14月份 */
    if (date.month <= 2)
    {
        date.year -= 1;
        date.month += 12;
    }
    iCentury = date.year / 100;
    date.year = date.year % 100;
    cWeek = ((iCentury / 4) - (iCentury * 2) + date.year + (date.year / 4) + (13 * (date.month + 1) / 5) + date.day - 1) % 7;
    cWeek = (cWeek < 0) ? (cWeek + 7) : cWeek;
    return (uint8_t)cWeek;
}

tmdateType stamp2date(uint64_t lStamp, int8_t cUTC)
{
    int64_t lDaysNumber = 0;
    uint32_t lYearTemp = 1970;
    uint8_t ucMonthTemp = 1;
    tmdateType tmpday;
    /* 加入时区值 */
    lStamp += cUTC * 3600;
    tmpday.cUTC = cUTC;
    /* 减去全部年份的整年天数（1天有86400秒） */
    for (lDaysNumber = lStamp / 86400; lDaysNumber >= 0; ++lYearTemp)
        lDaysNumber -= DAYS_OF_THE_YEAR(lYearTemp);
    /* 上面循环多计算了1年 */
    tmpday.year = lYearTemp - 1;
    /* 加上上面循环多减去的1年，减去当前年份下全部月份的整月天数 */
    for (lDaysNumber += DAYS_OF_THE_YEAR(tmpday.year); lDaysNumber >= 0; ++ucMonthTemp)
        lDaysNumber -= DAYS_OF_THE_MONTH(tmpday.year, ucMonthTemp);
    /* 上面循环多计算了1月 */
    tmpday.month = ucMonthTemp - 1;
    /* 加上上面循环多减去的1月 */
    lDaysNumber += DAYS_OF_THE_MONTH(tmpday.year, tmpday.month);
    /* 天从1开始计数 */
    tmpday.day = lDaysNumber + 1;
    tmpday.hour = lStamp / 3600 % 24;
    tmpday.minute = lStamp / 60 % 60;
    tmpday.second = lStamp % 60;
    tmpday.week = getWeek(tmpday);
    return tmpday;
}
uint64_t date2stamp(tmdateType *dateVal)
{
    uint64_t lDaysNumber = 0, lStamp = 0;
    uint32_t lYearTemp = 1970;
    uint8_t ucMonthTemp = 1;
    if (!(dateVal->year >= 1970 && dateVal->month > 0 && dateVal->month < 13 && dateVal->day > 0 && dateVal->day < 32 && dateVal->hour < 24 && dateVal->minute < 61 && dateVal->second < 61))
    {
        return 0;
    }
    for (lYearTemp = 1970; lYearTemp < dateVal->year; ++lYearTemp)
        lDaysNumber += DAYS_OF_THE_YEAR(lYearTemp);
    for (ucMonthTemp = 1; ucMonthTemp < dateVal->month; ++ucMonthTemp)
        lDaysNumber += DAYS_OF_THE_MONTH(dateVal->year, ucMonthTemp);
    lDaysNumber += dateVal->day - 1;
    lStamp = lDaysNumber * 86400;
    lStamp += dateVal->hour * 3600;
    lStamp += dateVal->minute * 60;
    lStamp += dateVal->second;
    /* 加入计算时区值 */
    lStamp -= dateVal->cUTC * 3600;
    return lStamp;
}
